package com.evan.common.utils;

import com.evan.common.bit.NodeModeEnum;
import com.evan.common.pojo.NodeData;
import org.apache.zookeeper.*;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class ZookeeperClient implements Watcher {

    private static final Logger LOG = LoggerFactory.getLogger(ZookeeperClient.class);

    private String connectString;
    private ZooKeeper zooKeeper;
    private int sessionTimeout = 5000;
    private CountDownLatch countDownLatch = new CountDownLatch(1);

    public ZookeeperClient(String hosts, int sessionTimeout) throws Exception{
        this.connectString = hosts;
        this.sessionTimeout = sessionTimeout;
        zooKeeper = new ZooKeeper(hosts,sessionTimeout,this);
        boolean isConnectIn = countDownLatch.await(20l, TimeUnit.SECONDS);
        if(isConnectIn){
            LOG.info("zookeeper server connection success.");
        }else{
            LOG.error("zookeeper server connection failed.");
        }
    }

    public boolean exists(String path,boolean watch) throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists(path, watch);
        return stat != null;
    }
    public boolean exists(String path) throws KeeperException, InterruptedException {
        return this.exists(path,false);
    }

    public Stat getZNodeStat(String path,boolean watch) throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists(path, watch);
        if(stat != null){
            return stat;
        }
        return null;
    }
    public Stat getZNodeStat(String path) throws KeeperException, InterruptedException {
        return this.getZNodeStat(path,false);
    }

    public NodeData getData(String path, boolean watcher, Stat stat) throws KeeperException, InterruptedException {
        byte[] data = zooKeeper.getData(path, watcher, stat);
        String res = "";
        if(data != null){
            res = new String(data);
        }
        NodeData nodeData = new NodeData();
        nodeData.setData(res);
        if(stat.getEphemeralOwner() != 0){
            nodeData.setNodeMode(NodeModeEnum.PERSISTENT);
        }else{
            nodeData.setNodeMode(NodeModeEnum.EPHEMERAL);
        }
        return nodeData;
    }

    public NodeData getData(String path) throws KeeperException, InterruptedException {
        return this.getData(path,false,new Stat());
    }

    public boolean setData(String path,String data) throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.setData(path, data.getBytes(), -1);
        return stat != null;
    }

    public String create(String path, byte[] bytes, CreateMode createMode) throws KeeperException, InterruptedException {
//        ZooDefs.Ids.CREATOR_ALL_ACL,
        String resPath = zooKeeper.create(path, bytes,ZooDefs.Ids.OPEN_ACL_UNSAFE, createMode);
        return resPath;
    }

    public void delete(String path) throws KeeperException, InterruptedException {
        zooKeeper.delete(path,-1);
    }

    public List<String> getChildren(String path,boolean watch) throws KeeperException, InterruptedException {
        List<String> childrenNodes = zooKeeper.getChildren(path, watch);
        return childrenNodes;
    }
    public List<String> getChildren(String path) throws KeeperException, InterruptedException {
         return this.zooKeeper.getChildren(path, false);
    }
    public boolean hasChildren(String path) throws KeeperException, InterruptedException {
        List<String> children = this.getChildren(path);
        if(children == null || children.size() == 0){
            return false;
        }
        return true;
    }

    public void releaseConnection(){
        try{
            if(zooKeeper != null){
                zooKeeper.close();
            }
            LOG.info("zookeeper  disconnect.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {

        if(event==null)
            return;
        if(Event.KeeperState.SyncConnected == event.getState()){
            if(Event.EventType.None == event.getType()){
                LOG.info("zookeeper server connection success.");
                countDownLatch.countDown();
            }
        }else if (Event.KeeperState.Disconnected == event.getState()) {
            System.out.println("zookeeper Disconnected");
        } else if (Event.KeeperState.AuthFailed == event.getState()) {
            System.out.println("zookeeper AuthFailed");
        } else if (Event.KeeperState.Expired == event.getState()) {
            System.out.println("zookeeper Expired");
        }

    }

}
